package ui;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;

import javax.imageio.ImageIO;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.table.DefaultTableModel;

import controller.CityController;
import controller.CountryController;
import controller.CustomerController;
import model.City;
import model.Country;
import model.Customer;
import util.ImagePanel;
import util.EmailValidator;
import util.MD5;
import util.Menu;
import util.PdfFilePrint;

public class CustomerUI implements ActionListener
{
	private boolean startup = false;

	private static CustomerUI instance = null;

	private CustomerController customerCtrl;
	private CountryController countryCtrl;
	private CityController cityCtrl;

	private EmailValidator emailValidator;

	private JMenuBar menu;

	private Menu menuBar;

	private JFrame frameCustomerUI;

	private JTabbedPane tabbedPane;

	private JPanel redPanel;

	private Image image = null;

	private ImagePanel newCustomer;
	private ImagePanel allCustomers;

	private JTable allCustomersTable;
	private DefaultTableModel allCustomersTableModel;

	private JComboBox<String> allCustomersComboBoxSearchType;
	private JComboBox<String> newCustomerComboBoxStatus;
	private JComboBox<String> newCustomerComboBoxCountry;
	private JComboBox<String> newCustomerComboBoxCity;
	private JComboBox<String> editCustomerComboBoxCountry;
	private JComboBox<String> editCustomerComboBoxCity;

	private JButton newCustomerButtonCreateCustomer;
	private JButton allCustomersButtonSearchClear;
	private JButton allCustomersButtonEditCustomer;
	private JButton allCustomersButtonDeactivateCustomer;
	private JButton btnPrint;
	private JButton statistics;

	private JCheckBox allCustomersCheckBoxOnlyActiveCustomers;

	private JTextField allCustomersTextFieldSearchFor;
	private JTextField newCustomerTextFieldUsername;
	private JTextField newCustomerTextFieldPhoneNo;
	private JTextField newCustomerTextFieldEmail;

	private JPasswordField newCustomerPasswordFieldSecond;
	private JPasswordField newCustomerPasswordFieldFirst;

	private ArrayList<JTextField> newCustomerTextFields;
	private ArrayList<JTextField> editCustomerTextFields;

	private ArrayList<JPasswordField> newCustomerPasswordFields;
	private ArrayList<JPasswordField> editCustomerPasswordFields;
	private JButton btnBack;

	private backButton back;


	public void display()
	{
		frameCustomerUI.getContentPane().add(redPanel);

		redPanel.add(tabbedPane);

		tabbedPane.add("All Customers", allCustomers);
		tabbedPane.add("New Customer", newCustomer);

		frameCustomerUI.setSize(800,420);
		frameCustomerUI.setLocationRelativeTo(null);
		frameCustomerUI.setVisible(true);
		frameCustomerUI.setResizable(false);
	}

	public CustomerUI()
	{
		back = new backButton();
		back.setNumber("3");

		frameCustomerUI = new JFrame("Customer UI");

		menuBar = Menu.getInstance();

		menu = menuBar.makeJMenuBar();

		frameCustomerUI.setJMenuBar(menu);

		redPanel = new JPanel();
		redPanel.setBackground(new Color(165, 42, 42));

		tabbedPane = new JTabbedPane();

		customerCtrl = new CustomerController();
		countryCtrl = new CountryController();
		cityCtrl = new CityController();
		emailValidator = new EmailValidator();

		try
		{
			image = ImageIO.read(new File("img/background/background.jpg"));
		} 
		catch (IOException e)
		{
			msgError(null, "Could not load background image");
		}

		JLabel redPanelLabelTitle = new JLabel("CUSTOMER MENU");
		redPanelLabelTitle.setForeground(Color.WHITE);
		redPanelLabelTitle.setFont(new Font("Arial Unicode MS", Font.BOLD, 20));

		statistics = new JButton();
		statistics.setLocation(590, 327);
		statistics.setSize(100, 20);
		statistics.setOpaque(false);
		statistics.setText("Statistics");
		statistics.addActionListener(this);

		btnBack = new JButton();
		btnBack.setText("Back");
		btnBack.setOpaque(false);
		btnBack.addActionListener(this);

		btnPrint = new JButton();
		btnPrint.addActionListener(this);
		btnPrint.setText("Print");
		btnPrint.setOpaque(false);

		GroupLayout gl_redTitle = new GroupLayout(redPanel);
		gl_redTitle.setHorizontalGroup(
				gl_redTitle.createParallelGroup(Alignment.TRAILING)
				.addComponent(tabbedPane, GroupLayout.DEFAULT_SIZE, 794, Short.MAX_VALUE)
				.addGroup(gl_redTitle.createSequentialGroup()
						.addContainerGap()
						.addComponent(redPanelLabelTitle, GroupLayout.PREFERRED_SIZE, 241, GroupLayout.PREFERRED_SIZE)
						.addContainerGap(543, Short.MAX_VALUE))
						.addGroup(gl_redTitle.createSequentialGroup()
								.addContainerGap()
								.addComponent(btnBack, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE)
								.addPreferredGap(ComponentPlacement.RELATED, 468, Short.MAX_VALUE)
								.addComponent(btnPrint, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE)
								.addPreferredGap(ComponentPlacement.RELATED)
								.addComponent(statistics, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE)
								.addContainerGap())
				);
		gl_redTitle.setVerticalGroup(
				gl_redTitle.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_redTitle.createSequentialGroup()
						.addComponent(redPanelLabelTitle)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(tabbedPane, GroupLayout.PREFERRED_SIZE, 309, GroupLayout.PREFERRED_SIZE)
						.addGap(5)
						.addGroup(gl_redTitle.createParallelGroup(Alignment.BASELINE)
								.addComponent(statistics, GroupLayout.PREFERRED_SIZE, 20, GroupLayout.PREFERRED_SIZE)
								.addComponent(btnBack, GroupLayout.PREFERRED_SIZE, 20, GroupLayout.PREFERRED_SIZE)
								.addComponent(btnPrint, GroupLayout.PREFERRED_SIZE, 20, GroupLayout.PREFERRED_SIZE))
								.addGap(20))
				);

		redPanel.setLayout(gl_redTitle);

		/******************************************************
		 * 
		 * New customer pane
		 * 
		 ******************************************************/

		newCustomer = new ImagePanel(image);

		JLabel newCustomerLabelName = new JLabel("Customer Username:");
		JLabel newCustomerLabelPassword = new JLabel("Customer Password:");
		JLabel newCustomerLabelPhoneno = new JLabel("Customer PhoneNo:");
		JLabel newCustomerLabelEmail = new JLabel("Customer E-mail:");
		JLabel newCustomerLabelStatus = new JLabel("Customer Status:");
		JLabel newCustomerLabelCountry = new JLabel("Customer Country:");
		JLabel newCustomerLabelCity = new JLabel("Customer City:");
		JLabel newCustomerLabelSoftware = new JLabel("Vaizdine Reklama Software v0.1");
		newCustomerLabelSoftware.setEnabled(false);

		newCustomerTextFieldUsername = new JTextField();
		newCustomerTextFieldUsername.setColumns(10);

		newCustomerTextFieldPhoneNo = new JTextField();
		newCustomerTextFieldPhoneNo.setColumns(10);

		newCustomerTextFieldEmail = new JTextField();
		newCustomerTextFieldEmail.setColumns(10);

		newCustomerComboBoxStatus = new JComboBox<String>();
		newCustomerComboBoxStatus.addItem("Active");
		newCustomerComboBoxStatus.addItem("Inactive");

		newCustomerComboBoxCountry = new JComboBox<String>();
		newCustomerComboBoxCountry.addActionListener(this);

		newCustomerComboBoxCity = new JComboBox<String>();
		newCustomerComboBoxCity.setEnabled(false);

		newCustomerButtonCreateCustomer = new JButton("Create Customer");
		newCustomerButtonCreateCustomer.setOpaque(false);
		newCustomerButtonCreateCustomer.addActionListener(this);
		newCustomerButtonCreateCustomer.setEnabled(false);

		newCustomerPasswordFieldSecond = new JPasswordField();
		newCustomerPasswordFieldFirst = new JPasswordField();

		newCustomerTextFields = new ArrayList<JTextField>();
		newCustomerTextFields.add(newCustomerTextFieldUsername);
		newCustomerTextFields.add(newCustomerTextFieldPhoneNo);
		newCustomerTextFields.add(newCustomerTextFieldEmail);

		newCustomerPasswordFields = new ArrayList<JPasswordField>();
		newCustomerPasswordFields.add(newCustomerPasswordFieldFirst);
		newCustomerPasswordFields.add(newCustomerPasswordFieldSecond);

		JLabel newCustomerLabelPasswordAgain = new JLabel("Customer Password Again:");
		GroupLayout gl_newCustomer = new GroupLayout(newCustomer);
		gl_newCustomer.setHorizontalGroup(
				gl_newCustomer.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_newCustomer.createSequentialGroup()
						.addGap(535)
						.addComponent(newCustomerLabelSoftware, GroupLayout.PREFERRED_SIZE, 254, Short.MAX_VALUE))
						.addGroup(gl_newCustomer.createSequentialGroup()
								.addGap(248)
								.addGroup(gl_newCustomer.createParallelGroup(Alignment.LEADING)
										.addComponent(newCustomerLabelPasswordAgain)
										.addComponent(newCustomerLabelPassword)
										.addComponent(newCustomerLabelPhoneno)
										.addComponent(newCustomerLabelEmail)
										.addComponent(newCustomerLabelStatus)
										.addComponent(newCustomerLabelCountry)
										.addComponent(newCustomerLabelCity)
										.addComponent(newCustomerLabelName))
										.addGap(15)
										.addGroup(gl_newCustomer.createParallelGroup(Alignment.TRAILING, false)
												.addComponent(newCustomerButtonCreateCustomer, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
												.addComponent(newCustomerComboBoxCountry, Alignment.LEADING, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
												.addComponent(newCustomerComboBoxStatus, Alignment.LEADING, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
												.addComponent(newCustomerTextFieldEmail, Alignment.LEADING)
												.addComponent(newCustomerTextFieldUsername, Alignment.LEADING)
												.addComponent(newCustomerPasswordFieldFirst, Alignment.LEADING)
												.addComponent(newCustomerPasswordFieldSecond, Alignment.LEADING)
												.addComponent(newCustomerTextFieldPhoneNo, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 149, Short.MAX_VALUE)
												.addComponent(newCustomerComboBoxCity, Alignment.LEADING, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
												.addContainerGap(248, Short.MAX_VALUE))
				);
		gl_newCustomer.setVerticalGroup(
				gl_newCustomer.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_newCustomer.createSequentialGroup()
						.addGap(22)
						.addGroup(gl_newCustomer.createParallelGroup(Alignment.BASELINE)
								.addComponent(newCustomerTextFieldUsername, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
								.addComponent(newCustomerLabelName))
								.addPreferredGap(ComponentPlacement.RELATED)
								.addGroup(gl_newCustomer.createParallelGroup(Alignment.BASELINE)
										.addComponent(newCustomerPasswordFieldFirst, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
										.addComponent(newCustomerLabelPassword))
										.addPreferredGap(ComponentPlacement.RELATED)
										.addGroup(gl_newCustomer.createParallelGroup(Alignment.BASELINE)
												.addComponent(newCustomerPasswordFieldSecond, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
												.addComponent(newCustomerLabelPasswordAgain))
												.addPreferredGap(ComponentPlacement.RELATED)
												.addGroup(gl_newCustomer.createParallelGroup(Alignment.BASELINE)
														.addComponent(newCustomerTextFieldPhoneNo, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
														.addComponent(newCustomerLabelPhoneno))
														.addPreferredGap(ComponentPlacement.RELATED)
														.addGroup(gl_newCustomer.createParallelGroup(Alignment.BASELINE)
																.addComponent(newCustomerTextFieldEmail, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
																.addComponent(newCustomerLabelEmail))
																.addPreferredGap(ComponentPlacement.RELATED)
																.addGroup(gl_newCustomer.createParallelGroup(Alignment.BASELINE)
																		.addComponent(newCustomerComboBoxStatus, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
																		.addComponent(newCustomerLabelStatus))
																		.addPreferredGap(ComponentPlacement.RELATED)
																		.addGroup(gl_newCustomer.createParallelGroup(Alignment.BASELINE)
																				.addComponent(newCustomerComboBoxCountry, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
																				.addComponent(newCustomerLabelCountry))
																				.addPreferredGap(ComponentPlacement.RELATED)
																				.addGroup(gl_newCustomer.createParallelGroup(Alignment.BASELINE)
																						.addComponent(newCustomerComboBoxCity, GroupLayout.PREFERRED_SIZE, 20, GroupLayout.PREFERRED_SIZE)
																						.addComponent(newCustomerLabelCity))
																						.addPreferredGap(ComponentPlacement.UNRELATED)
																						.addComponent(newCustomerButtonCreateCustomer)
																						.addGap(72)
																						.addComponent(newCustomerLabelSoftware, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
				);
		newCustomer.setLayout(gl_newCustomer);

		/******************************************************
		 * 
		 * All customers pane
		 * 
		 ******************************************************/

		allCustomers = new ImagePanel(image);

		String allCustomersColumns [] = { "#", "Username", "PhoneNo", "Email", "City", "Country", "", "Active" };
		allCustomersTableModel = new DefaultTableModel(null, allCustomersColumns);

		allCustomersTable = new JTable(allCustomersTableModel)
		{
			private static final long serialVersionUID = 1L;

			public boolean isCellEditable(int rowIndex, int colIndex) 
			{
				return false;
			}

			public Class<?> getColumnClass(int column)   
			{   
				return getValueAt(0, column).getClass();   
			}  
		};

		Dimension dim = allCustomersTable.getPreferredSize(); 
		double width = dim.width / allCustomersColumns.length; 
		double[] width_2 = { 0.3, 1.2, 1.2, 2, 1, 1, 0.5, 0.5 };

		for (int i = 0; i < allCustomersColumns.length; i++)
			allCustomersTable.getColumnModel().getColumn(i).setPreferredWidth((int) (width*width_2[i])); 

		allCustomersTable.setAutoCreateRowSorter(true);

		allCustomersTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		JScrollPane allCustomersTableScroll = new JScrollPane(allCustomersTable);

		JLabel allCustomersLabelSearchBy = new JLabel("Search by:");
		JLabel allCustomersLabelSearchFor = new JLabel("Search for:");

		allCustomersComboBoxSearchType = new JComboBox<String>();
		allCustomersComboBoxSearchType.addActionListener(this);
		allCustomersComboBoxSearchType.addItem("Everything");
		allCustomersComboBoxSearchType.addItem("Username");
		allCustomersComboBoxSearchType.addItem("Email");
		allCustomersComboBoxSearchType.addItem("PhoneNo");
		allCustomersComboBoxSearchType.addItem("City");
		allCustomersComboBoxSearchType.addItem("Country");

		allCustomersTextFieldSearchFor = new JTextField();
		allCustomersTextFieldSearchFor.getDocument().addDocumentListener(new DocumentListener()
		{
			@Override
			public void insertUpdate(DocumentEvent e)
			{
				// most likely to never be used .. 
				searchCustomers();						
			}

			@Override
			public void changedUpdate(DocumentEvent e)
			{
				searchCustomers();
			}

			@Override
			public void removeUpdate(DocumentEvent e)
			{
				searchCustomers();
			}
		});

		allCustomersButtonSearchClear = new JButton("Clear Search");
		allCustomersButtonSearchClear.setOpaque(false);
		allCustomersButtonSearchClear.addActionListener(this);

		allCustomersButtonEditCustomer = new JButton("Edit Customer");
		allCustomersButtonEditCustomer.setOpaque(false);
		allCustomersButtonEditCustomer.addActionListener(this);

		allCustomersButtonDeactivateCustomer = new JButton("Change Status");
		allCustomersButtonDeactivateCustomer.setOpaque(false);
		allCustomersButtonDeactivateCustomer.addActionListener(this);

		allCustomersCheckBoxOnlyActiveCustomers = new JCheckBox("Only active customers");
		allCustomersCheckBoxOnlyActiveCustomers.setOpaque(false);
		allCustomersCheckBoxOnlyActiveCustomers.setSelected(true);
		allCustomersCheckBoxOnlyActiveCustomers.addActionListener(this);

		GroupLayout gl_allCustomers = new GroupLayout(allCustomers);
		gl_allCustomers.setHorizontalGroup(
				gl_allCustomers.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_allCustomers.createSequentialGroup()
						.addContainerGap()
						.addGroup(gl_allCustomers.createParallelGroup(Alignment.TRAILING)
								.addComponent(allCustomersTableScroll, GroupLayout.DEFAULT_SIZE, 769, Short.MAX_VALUE)
								.addGroup(gl_allCustomers.createSequentialGroup()
										.addGroup(gl_allCustomers.createParallelGroup(Alignment.LEADING)
												.addComponent(allCustomersLabelSearchBy)
												.addComponent(allCustomersLabelSearchFor))
												.addPreferredGap(ComponentPlacement.RELATED)
												.addGroup(gl_allCustomers.createParallelGroup(Alignment.LEADING, false)
														.addComponent(allCustomersTextFieldSearchFor, GroupLayout.PREFERRED_SIZE, 161, GroupLayout.PREFERRED_SIZE)
														.addComponent(allCustomersComboBoxSearchType, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
														.addPreferredGap(ComponentPlacement.RELATED)
														.addGroup(gl_allCustomers.createParallelGroup(Alignment.LEADING)
																.addGroup(gl_allCustomers.createSequentialGroup()
																		.addComponent(allCustomersButtonSearchClear)
																		.addPreferredGap(ComponentPlacement.RELATED, 209, Short.MAX_VALUE)
																		.addComponent(allCustomersButtonEditCustomer)
																		.addPreferredGap(ComponentPlacement.UNRELATED)
																		.addComponent(allCustomersButtonDeactivateCustomer))
																		.addComponent(allCustomersCheckBoxOnlyActiveCustomers))))
																		.addContainerGap())
				);
		gl_allCustomers.setVerticalGroup(
				gl_allCustomers.createParallelGroup(Alignment.TRAILING)
				.addGroup(gl_allCustomers.createSequentialGroup()
						.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
						.addGroup(gl_allCustomers.createParallelGroup(Alignment.BASELINE)
								.addComponent(allCustomersLabelSearchBy)
								.addComponent(allCustomersComboBoxSearchType, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
								.addComponent(allCustomersCheckBoxOnlyActiveCustomers))
								.addPreferredGap(ComponentPlacement.RELATED)
								.addGroup(gl_allCustomers.createParallelGroup(Alignment.BASELINE)
										.addComponent(allCustomersLabelSearchFor)
										.addComponent(allCustomersTextFieldSearchFor, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
										.addComponent(allCustomersButtonSearchClear)
										.addComponent(allCustomersButtonDeactivateCustomer)
										.addComponent(allCustomersButtonEditCustomer))
										.addPreferredGap(ComponentPlacement.RELATED)
										.addComponent(allCustomersTableScroll, GroupLayout.PREFERRED_SIZE, 204, GroupLayout.PREFERRED_SIZE)
										.addGap(63))
				);
		allCustomers.setLayout(gl_allCustomers);

		try
		{
			searchCustomers();
			updateCountries(newCustomerComboBoxCountry, true);
		}
		catch (Exception e)
		{
			msgError(allCustomers, "Could not load properly");
		}
	}

	/**
	 * ActionPerformed.. where all the magic happens.
	 * Our listener for every action which happens.
	 * 
	 * @param 	e		the event which has triggered the listener
	 * 
	 * @return 	void 
	 */
	@Override
	public void actionPerformed(ActionEvent e)
	{
		frameCustomerUI.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

		if (e.getSource() == allCustomersCheckBoxOnlyActiveCustomers)
		{
			searchCustomers();
		}
		if(e.getSource() == statistics)
		{
			StatisticsUI stats = StatisticsUI.getInstance();
			stats.display();
			frameCustomerUI.setVisible(false);
		}
		else if (e.getSource() == allCustomersButtonSearchClear)
		{

			allCustomersComboBoxSearchType.setSelectedIndex(0);
			allCustomersTextFieldSearchFor.setText(null);

			searchCustomers();
		}
		else if (e.getSource() == allCustomersComboBoxSearchType)
		{
			if (startup)
			{
				allCustomersTextFieldSearchFor.setText(null);

				searchCustomers();
			}
		}
		else if (e.getSource() == allCustomersButtonEditCustomer)
		{
			showEditCustomerDialog();
		}
		else if (e.getSource() == newCustomerComboBoxCountry) 
		{
			updateCities((newCustomerComboBoxCountry.getSelectedIndex() > 0), newCustomerComboBoxCity, newCustomerComboBoxCountry);
		}
		else if (e.getSource() == editCustomerComboBoxCountry)
		{
			updateCities(true, editCustomerComboBoxCity, editCustomerComboBoxCountry);
		}
		else if (e.getSource() == newCustomerButtonCreateCustomer)
		{
			addCustomer();
		}
		else if (e.getSource() == allCustomersButtonDeactivateCustomer)
		{
			activateCustomer();
		}
		else if(e.getSource() == btnBack)
		{
			back.goBack(back.getNumber());
		}
		else if(e.getSource() == btnPrint)
		{
			printCustomerPDF();
		}

		frameCustomerUI.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}

	private void printCustomerPDF()
	{
		if (allCustomersTable.getRowCount() > 0)
		{
			ArrayList<ArrayList<String>> list = new ArrayList<ArrayList<String>>();

			String columns[] = { "ID", "Username", "PhoneNo", "Email", "City", "Country", "Active" };
			ArrayList<String> customerID = new ArrayList<String>();
			ArrayList<String> customerUsername = new ArrayList<String>();
			ArrayList<String> customerPhoneNo = new ArrayList<String>();
			ArrayList<String> customerEmail = new ArrayList<String>();
			ArrayList<String> customerCity = new ArrayList<String>();
			ArrayList<String> customerCountry = new ArrayList<String>();
			ArrayList<String> customerActive = new ArrayList<String>();

			list.add(customerID);
			list.add(customerUsername);
			list.add(customerPhoneNo);
			list.add(customerEmail);
			list.add(customerCity);
			list.add(customerCountry);
			list.add(customerActive);

			for(int i = 0; i < allCustomersTable.getRowCount(); i++)
			{
				list.get(0).add(String.valueOf(allCustomersTable.getValueAt(i, 0)));
				list.get(1).add(String.valueOf(allCustomersTable.getValueAt(i, 1)));
				list.get(2).add(String.valueOf(allCustomersTable.getValueAt(i, 2)));
				list.get(3).add(String.valueOf(allCustomersTable.getValueAt(i, 3)));
				list.get(4).add(String.valueOf(allCustomersTable.getValueAt(i, 4)));
				list.get(5).add(String.valueOf(allCustomersTable.getValueAt(i, 5)));
				list.get(6).add(String.valueOf(allCustomersTable.getValueAt(i, 7)).contains("yes") ? "Yes" : "No");
			}

			PdfFilePrint pdfPrint = new PdfFilePrint();
			boolean successPDF = pdfPrint.PDFPrint("Customer", "Current Customers", "customer", "Nikola", columns, list);

			if(successPDF)
				msgSuccess(null, "PDF was created successfully");
			else
				msgError(null, "There was an error creating the PDF");
		}
		else
		{
			msgError(null, "Nothing to print");
		}
	}

	/**
	 * Necessary checks when adding a customer
	 * 
	 * @return	void
	 */
	private void addCustomer()
	{
		boolean validInfo = customerCheckValidInfo(newCustomerTextFields, newCustomerPasswordFields, true);
		boolean validPassword = customerCheckValidPassword(newCustomerPasswordFieldFirst, newCustomerPasswordFieldSecond);
		boolean validEmail = emailValidator.validate(newCustomerTextFieldEmail.getText());

		if (validInfo && validPassword && validEmail)
		{
			try
			{
				int success = customerCtrl.createCustomer(newCustomerTextFieldUsername.getText(), new String(newCustomerPasswordFieldFirst.getPassword()), (newCustomerComboBoxStatus.getSelectedItem() == "Active"), cityCtrl.getOneCity("name",newCustomerComboBoxCity.getSelectedItem().toString(), newCustomerComboBoxCountry.getSelectedItem().toString()), newCustomerTextFieldEmail.getText(), newCustomerTextFieldPhoneNo.getText());

				if (success > 0)
				{
					msgSuccess(newCustomer, "Customer \"" + newCustomerTextFieldUsername.getText() + "\" has been added successfully");

					for(JTextField tf : newCustomerTextFields)
						tf.setText(null);

					for (JPasswordField pf : newCustomerPasswordFields)
						pf.setText(null);	

					searchCustomers();
					updateCountries(newCustomerComboBoxCountry, true);
				}
				else
				{
					msgError(newCustomer, "There was an error adding the customer.\nThis username already exists in the system.");					
				}
			}
			catch (Exception ex)
			{
				msgError(newCustomer, "There was an error adding the customer.\nThis username already exists in the system.");
			}
		}
		else 
		{
			String error = "You cannot proceed due some errors:\n\n";

			if (!validInfo)
				error += " - You haven't filled up every text area\n";

			if (!validPassword)
				error += " - The two passwords do not match\n";	

			if (!validEmail)
				error += " - Email is not valid\n";

			msgError(newCustomer, error);
		}		
	}

	/**
	 * Necessary checks (and dialog opening) when editing a customer
	 * 
	 * @return	void
	 */
	private void showEditCustomerDialog()
	{
		if (allCustomersTable.getSelectedRow() > -1) 
		{
			try
			{
				int customerID = Integer.valueOf(String.valueOf(allCustomersTable.getValueAt(allCustomersTable.getSelectedRow(), 0)));
				Customer editCustomer = customerCtrl.searchCustomerID(customerID);

				JPanel panel = new JPanel(new GridLayout(0, 2, 5, 5));

				JTextField editCustomerTextFieldCustomerName = new JTextField(editCustomer.getUsername());
				JTextField editCustomerTextFieldCustomerPhoneNo = new JTextField(editCustomer.getPhoneNo());
				JTextField editCustomerTextFieldCustomerEmail = new JTextField(editCustomer.getEmail());

				JPasswordField editCustomerPasswordFieldFirst = new JPasswordField(null);
				JPasswordField editCustomerPasswordFieldSecond = new JPasswordField(null);

				JComboBox<String> editCustomerComboBoxActive = new JComboBox<String>();
				editCustomerComboBoxActive.addItem("Active");
				editCustomerComboBoxActive.addItem("Inactive");
				editCustomerComboBoxActive.setSelectedIndex(editCustomer.isActive() ? 0 : 1);

				editCustomerComboBoxCountry = new JComboBox<String>();
				updateCountries(editCustomerComboBoxCountry, false);
				editCustomerComboBoxCountry.setSelectedItem(editCustomer.getCity().getCountry().getName());
				editCustomerComboBoxCountry.addActionListener(this);

				editCustomerComboBoxCity = new JComboBox<String>();
				updateCities(true, editCustomerComboBoxCity, editCustomerComboBoxCountry);
				editCustomerComboBoxCity.setSelectedItem(editCustomer.getCity().getName());

				panel.add(new JLabel("Customer Name:"));
				panel.add(editCustomerTextFieldCustomerName);
				panel.add(new JLabel("Customer Password:"));
				panel.add(editCustomerPasswordFieldFirst);
				panel.add(new JLabel("Customer Password Again:"));
				panel.add(editCustomerPasswordFieldSecond);
				panel.add(new JLabel("Customer PhoneNo:"));
				panel.add(editCustomerTextFieldCustomerPhoneNo);
				panel.add(new JLabel("Customer E-mail:"));
				panel.add(editCustomerTextFieldCustomerEmail);
				panel.add(new JLabel("Customer Status:"));
				panel.add(editCustomerComboBoxActive);
				panel.add(new JLabel("Customer Country:"));
				panel.add(editCustomerComboBoxCountry);
				panel.add(new JLabel("Customer City:"));
				panel.add(editCustomerComboBoxCity);

				editCustomerTextFields = new ArrayList<JTextField>();
				editCustomerTextFields.add(editCustomerTextFieldCustomerName);
				editCustomerTextFields.add(editCustomerTextFieldCustomerPhoneNo);
				editCustomerTextFields.add(editCustomerTextFieldCustomerEmail);

				editCustomerPasswordFields = new ArrayList<JPasswordField>();
				editCustomerPasswordFields.add(editCustomerPasswordFieldFirst);
				editCustomerPasswordFields.add(editCustomerPasswordFieldSecond);

				int option = JOptionPane.showConfirmDialog(allCustomers, panel, "Edit customer", JOptionPane.OK_CANCEL_OPTION);

				if (option == JOptionPane.YES_OPTION)
				{
					boolean validInfo = customerCheckValidInfo(editCustomerTextFields, editCustomerPasswordFields, false);
					boolean validPassword = customerCheckValidPassword(editCustomerPasswordFieldFirst, editCustomerPasswordFieldSecond);
					boolean validEmail = emailValidator.validate(editCustomerTextFieldCustomerEmail.getText());

					if (validInfo && validPassword && validEmail)
					{
						String password = editCustomerPasswordFieldFirst.getPassword().length > 0 ? MD5.md5(new String(editCustomerPasswordFieldFirst.getPassword())) : editCustomer.getPassword();

						int success = customerCtrl.updateCustomer(customerID, editCustomerTextFieldCustomerName.getText(), password, (editCustomerComboBoxActive.getSelectedIndex() == 0 ? true : false), cityCtrl.getOneCity("name", editCustomerComboBoxCity.getSelectedItem().toString(), editCustomerComboBoxCountry.getSelectedItem().toString()), editCustomerTextFieldCustomerEmail.getText(), editCustomerTextFieldCustomerPhoneNo.getText());

						if (success > 0)
						{
							msgSuccess(newCustomer, "Customer #" + customerID + " has been edited successfully");

							searchCustomers();
						}
						else 
						{
							msgError(newCustomer, "There was an error adding the customer.\nThis username already exists in the system.");					
						}
					}
					else 
					{
						String error = "You cannot proceed due some errors:\n\n";

						if (!validInfo)
							error += " - You haven't filled up every text area or a field has more than 32 symbols\n";

						if (!validPassword)
							error += " - The two passwords do not match\n";	

						if (!validEmail)
							error += " - Email is not valid\n";

						msgError(newCustomer, error);
					}
				}
			}
			catch (SQLException | NoSuchAlgorithmException ex)
			{
				msgError(allCustomers, "There was a problem loading the customer");
			}
		}
		else 
		{
			msgError(allCustomers, "You have not selected a customer");
		}
	}

	/**
	 * Returns if the two ArrayLists which are given are not empty or the length
	 * is more than 32 symbols.
	 *
	 * @param  	textFields  		an array list with all the text fields which need to be checked
	 * @param  	passwordFields 		an array list with all the password fields which need to be checked
	 * @param	checkPass			if it will check the password or not
	 * 
	 * @return	true 				if they are not empty
	 */
	private boolean customerCheckValidInfo(ArrayList<JTextField> textFields, ArrayList<JPasswordField> passwordFields, boolean checkPass)
	{
		for(JTextField tf : textFields)
		{
			if ((tf.getText().trim().length() == 0) || (tf.getText().length() > 32))
				return false;
		}

		if (checkPass)
		{
			for(JPasswordField pf : passwordFields)
			{
				if (pf.getPassword().length == 0)
					return false;
			}
		}

		return true;
	}

	/**
	 * Checks if two password fields are equal
	 *
	 * @param 	passwordFieldFirst		password field one
	 * @param  	passwordFieldSecond 	password field two
	 * 
	 * @return	boolean					if they are the same
	 */
	private boolean customerCheckValidPassword(JPasswordField passwordFieldFirst, JPasswordField passwordFieldSecond)
	{
		if (!Arrays.equals(passwordFieldFirst.getPassword(), passwordFieldSecond.getPassword()))
			return false;

		return true;
	}

	/**
	 * Updates a certain JComboBox by adding all the cities from a certain
	 * selected country on another JComboBox
	 *
	 * @param  	notEmpty			should the city combo box be empty or not
	 * @param  	cityComboBox		the combo box which will be updated after calling this method
	 * @param	countryComboBox		the combo box from which we get the selected city in order to show only cities from this country
	 * 
	 * @return	void
	 */
	private void updateCities(boolean notEmpty, JComboBox<String> cityComboBox, JComboBox<String> countryComboBox)
	{
		cityComboBox.removeAllItems();
		cityComboBox.setEnabled(notEmpty);
		newCustomerButtonCreateCustomer.setEnabled(notEmpty);

		if (notEmpty)
		{
			ArrayList<City> cityList = null;

			try
			{
				cityList = cityCtrl.getCitiesByCountryName(countryComboBox.getSelectedItem().toString());

				for(City city : cityList)
				{
					cityComboBox.addItem(city.getName());
				}
			}
			catch(Exception e)
			{
				msgError(newCustomer, "Could not load cities or this country has no cities set");
			}
		}
	}

	/**
	 * Updates a certain JComboBox by adding all the countries
	 *
	 * @param  	comboBox		the combo box which will be updated after calling this method
	 * @param	emptyField		should the combo box have one empty field on top
	 * 
	 * @return	void
	 */
	private void updateCountries(JComboBox<String> comboBox, boolean emptyField)
	{
		comboBox.removeAllItems();

		if (emptyField)
			comboBox.addItem(null);

		ArrayList<Country> countryList = null;

		try
		{
			countryList = countryCtrl.getAllCountries();

			for(Country country : countryList)
				comboBox.addItem(country.getName());
		}
		catch(Exception e)
		{
			msgError(newCustomer, "Could not load countries");
		}
	}

	/**
	 * Updating the all customers table
	 *
	 * @param  	custList 	the array list which is put in the table
	 * 
	 * @return	void
	 */
	private void allCustomersUpdateTable(ArrayList<Customer> custList)
	{
		if (custList.size() > 0)
		{
			tableClearList();

			for(Customer customer : custList)
			{
				allCustomersTableModel.addRow(
						new Object[]
								{ 
								customer.getPersonID(), 
								customer.getUsername(),
								customer.getPhoneNo(),
								customer.getEmail(),
								customer.getCity().getName(),
								customer.getCity().getCountry().getName(),
								new ImageIcon("img/flags/" + customer.getCity().getCountry().getTld() + ".png"),
								new ImageIcon("img/tick_" + (customer.isActive() ? "yes" : "no") + ".png")
								} 
						);
			}
		}
	}

	/**
	 * Removing all rows from the all customer table
	 *
	 * @return	void
	 */
	private void tableClearList()
	{
		DefaultTableModel dm = (DefaultTableModel) allCustomersTable.getModel();

		while(dm.getRowCount() > 0)
			dm.removeRow(0);
	}

	/**
	 * Activating/deactivating a customer
	 *
	 * @return	void
	 */
	public void activateCustomer()
	{
		DefaultTableModel model = (DefaultTableModel) allCustomersTable.getModel();
		int[] rows = allCustomersTable.getSelectedRows();

		for (int i = 0; i < rows.length; i++)
		{
			int customerID = Integer.valueOf((String.valueOf(model.getValueAt(rows[i]-i,0))));

			try
			{
				if (customerCtrl.activateCustomer(customerID) > 0)
				{
					msgSuccess(allCustomers, "Successfully changed " + String.valueOf(model.getValueAt(rows[i]-i,1)) + "'s status");

					searchCustomers();
				}
			}
			catch (SQLException e)
			{
				msgError(allCustomers, "There was an error changing " + String.valueOf(model.getValueAt(rows[i]-i,1)) + "'s status");
			}
		}
	}

	/**
	 * Searching customer based on the selected drop down criteria 
	 * and input text field
	 * 
	 * @return	void
	 */
	private void searchCustomers()
	{
		ArrayList<Customer> custList = new ArrayList<Customer>();
		String clause = allCustomersComboBoxSearchType.getSelectedItem().toString().toLowerCase();
		String search = allCustomersTextFieldSearchFor.getText();

		try
		{
			boolean active = allCustomersCheckBoxOnlyActiveCustomers.isSelected();

			switch (clause)
			{
				case "city":		custList = customerCtrl.searchCustomerCity(active, search); break;
				case "country":		custList = customerCtrl.searchCustomerCountry(active, search); break;
				case "email": 		custList = customerCtrl.searchCustomerEmail(active, search); break;
				case "phoneno":		custList = customerCtrl.searchCustomerPhoneNo(active, search); break;
				case "username":	custList = customerCtrl.searchCustomerName(active, search); break;
				case "everything":	custList = customerCtrl.searchCustomerEverything(active, search); break;
			}

			if (custList.size() > 0)
				allCustomersUpdateTable(custList);
			else
				tableClearList();
		}
		catch (Exception e)
		{
			msgError(allCustomers, "Could not load customers");
		}

		if (!startup)
			startup = true;
	}

	/**
	 * Shows an error message pop-up
	 * 
	 * @param	panel 		on which panel should it show the message
	 * @param	error		the error which is printed on the pop-up window
	 * 
	 * @return	void
	 */
	private void msgError(JPanel panel, String error)
	{
		JOptionPane.showConfirmDialog(panel, error, "Error", JOptionPane.PLAIN_MESSAGE, JOptionPane.ERROR_MESSAGE);
	}

	/**
	 * Shows a success message pop-up
	 * 
	 * @param	panel 		on which panel should it show the message
	 * @param	success		the success message which is printed on the pop-up window
	 * 
	 * @return	void
	 */
	private void msgSuccess(JPanel panel, String success)
	{
		JOptionPane.showMessageDialog(panel, success, "Success", 1);
	}

	public static CustomerUI getInstance()
	{
		if(instance == null)
			instance = new CustomerUI();

		return instance;			
	}

	public static void main(String[] args)
	{
		try 
		{
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 

			CustomerUI customerMenu = new CustomerUI();
			customerMenu.display();
		}
		catch(Exception e)
		{
			JOptionPane.showMessageDialog(null, "Customer Menu could not load");
		}
	}
}